package com.hissy.cn.task;

import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by zhangyanfei on 2019/1/28.
 *
 * @author zhangyanfei
 * @date 2019/01/28
 *
 * /**
 * 异步任务服务框架
 * 1. 特点: 精简, 易用, 强类型, 即用即弃.
 * 1. 支持Exception转发
 * 2. 支持进度汇报 (可选)
 *
 * 代码示例:
 *
 * Bean注册:
 *
 * // 开始一个异步任务
 * String taskId = asyncTaskService.start(progressReporter -> {
 *
 *     // 执行逻辑
 *     for (int i = 0; i < 2; ++i) {
 *         sleepSeconds(1);
 *     }
 *
 *     // 返回结果
 *     return true;
 * });
 *
 * // 前端轮询查询结果, null为任务进行中, 非null为任务结果.
 * // getProgress方法用于获取进度
 * // getResult方法用于获取结果
 * while (true) {
 *
 *     Boolean result = asyncTaskService.getResult(taskId, Boolean.class);
 *
 *     if (result != null) {
 *         print(result);
 *         break;
 *     }
 *
 *     sleepSeconds(1);
 * }
 */
public class AsyncTaskService {
    static String TASK_PROGRESS_FOLDER = "task_progress";
    static String TASK_RESULT_FOLDER = "task_result";
    static String TASK_EXCEPTION_FOLDER = "task_exception";
    /**
     *20个固定线程
     */
    static ExecutorService executor = Executors.newFixedThreadPool(20);
    final static int TTL_SECONDS = 3600;
    static final Logger logger = LoggerFactory.getLogger(AsyncTaskService.class);

    public AsyncTaskService(){
        // 优雅停机 设置一个钩子  bean销毁规则
        Runtime.getRuntime().addShutdownHook(new Thread(()->{
            logger.info("停机信号收到，优雅停机中");
            // 停止接收任务
            executor.shutdown();
            try{
                // 最多等待30s
                executor.awaitTermination(30, TimeUnit.SECONDS);
                logger.info("优雅停机完毕");
            }catch (InterruptedException e){

            }
        }));
    }

    public void resetThreadCount(int threadCount){
        executor.shutdown();
        executor=Executors.newFixedThreadPool(threadCount);
    }

    public String start(int db,FunctionWithException<Object,Action<Progress>> task) {
        //任务id (本机相关)
        String taskId = UUID.randomUUID().toString();

        // 初始化任务进度
        Progress progress = new Progress();
        setKv(db,TASK_PROGRESS_FOLDER,progress);

        //提交任务
        executor.execute(()->{
            // 执行任务
            Exception exception=null;
            boolean hasSystemError=false;

            try{
                // 外部传入进度条
                Object result=task.invoke(newProcess->{
                    progress.copyFrom(newProcess);
                    setKv(db,TASK_PROGRESS_FOLDER,progress);
                });
                setKv(db,TASK_RESULT_FOLDER,result);
            }catch (Exception e){
                hasSystemError = true;
                exception=e;
            }

            // 打系统异常的错误日志
            if (hasSystemError) {
                logger.error(String.format("任务执行错误. taskId: %s", taskId), exception);
            }

            // 保存异常??
            if (exception != null) {
                setKv(db,TASK_EXCEPTION_FOLDER, exception);
            }

            // 任务进度完成
            progress.percent = 100;
           setKv(db,TASK_PROGRESS_FOLDER, progress);
        });

        return taskId;
    }

    private void setKv(int db,String floder,Object value){
        if(db==-1){
        }else{
        }
    }

    public <T> T getResult(int db,String taskId,Class<T> clazz){
        T result=null;
        if(db==-1){

        }
        return result;
    }



}
